from ctypes import *
import skf_api as skf_def  # 导入封装定义的模块，这里起了别名skf_def方便使用

# 加载动态库
skfapi_dll = cdll.LoadLibrary("mtoken_gm3000.dll")
# 设置函数原型
skf_def.set_function_prototypes(skfapi_dll)

def main():
    ulRslt = skf_def.ULONG(skf_def.SAR_OK)
    hdev = skf_def.HANDLE(None)
    happ = skf_def.HANDLE(None)
    hcont = skf_def.HANDLE(None)
    hkey = skf_def.HANDLE(None)
    szDevName = create_string_buffer(256)
    szAppName = create_string_buffer(256)
    szContName = create_string_buffer(256)
    pUserPin = b"123456"
    ulDevNameLen = skf_def.ULONG(256)
    ulAppNameLen = skf_def.ULONG(256)
    ulContNameLen = skf_def.ULONG(256)
    ulRetryCount = skf_def.ULONG(0)
    ulHashDataLen = skf_def.ULONG(256)
    ecc_pub = skf_def.ECCPUBLICKEYBLOB()
    ecc_sign = skf_def.ECCSIGNATUREBLOB()
    ulEccpubLen = skf_def.ULONG(sizeof(skf_def.ECCPUBLICKEYBLOB))
    # bp = skf_def.BLOCKCIPHERPARAM()
    pappname = szAppName
    idlen = 16
    pdevname = szDevName
    pcontname = szContName
    # 变量类型转换：BYTE *pbData 同时需要改变上面的c_ubyte为POINTER(c_ubyte)。
    pHashData = create_string_buffer(256)
    pHashDataPointer = cast(pHashData, POINTER(c_ubyte))
    pubid = b"1234567812345678"
    # 获取pubid的长度
    pubid_len = len(pubid)
    # 创建一个c_ubyte类型的数组，长度与pubid字节串长度一致
    pubid_array = (c_ubyte * pubid_len)(*pubid)
    psrcdata = b"1234567812345678"
    psrcdata_len = len(psrcdata)
    psrcdata_array = (c_ubyte * psrcdata_len)(*psrcdata)


    # 调用SKF_EnumDev函数
    ulRslt.value = skfapi_dll.SKF_EnumDev(skf_def.BOOL(True), szDevName, byref(ulDevNameLen))
    if ulRslt.value!= skf_def.SAR_OK:
        return
    # 调用SKF_ConnectDev函数
    ulRslt.value = skfapi_dll.SKF_ConnectDev(pdevname, byref(hdev))
    if ulRslt.value!= skf_def.SAR_OK:
        return
    # 调用SKF_EnumApplication函数
    ulRslt.value = skfapi_dll.SKF_EnumApplication(hdev, szAppName, byref(ulAppNameLen))
    if ulRslt.value!= skf_def.SAR_OK:
        return
    # 调用SKF_OpenApplication函数
    ulRslt.value = skfapi_dll.SKF_OpenApplication(hdev, pappname, byref(happ))
    if ulRslt.value!= skf_def.SAR_OK:
        return
    # 调用SKF_VerifyPIN函数
    ulRslt.value = skfapi_dll.SKF_VerifyPIN(happ, skf_def.ULONG(skf_def.USER_TYPE), pUserPin, byref(ulRetryCount))
    if ulRslt.value!= skf_def.SAR_OK:
        return
    # 调用SKF_EnumContainer函数
    ulRslt.value = skfapi_dll.SKF_EnumContainer(happ, szContName, byref(ulContNameLen))
    if ulRslt.value!= skf_def.SAR_OK:
        return
    # 调用SKF_OpenContainer函数
    ulRslt.value = skfapi_dll.SKF_OpenContainer(happ, pcontname, byref(hcont))
    if ulRslt.value!= skf_def.SAR_OK:
        return
    # 调用SKF_GenECCKeyPair函数
    ulRslt.value = skfapi_dll.SKF_GenECCKeyPair(hcont, skf_def.ULONG(skf_def.SGD_SM2_1), byref(ecc_pub))
    if ulRslt.value!= skf_def.SAR_OK:
        return
    # 调用SKF_ExportPublicKey函数
    ulRslt.value = skfapi_dll.SKF_ExportPublicKey(hcont, skf_def.BOOL(True), byref(ecc_pub), byref(ulEccpubLen))
    if ulRslt.value!= skf_def.SAR_OK:
        return
    # 调用SKF_DigestInit函数
    ulRslt.value = skfapi_dll.SKF_DigestInit(hdev, skf_def.ULONG(skf_def.SGD_SM3), byref(ecc_pub), pubid_array, idlen, byref(hkey))
    if ulRslt.value!= skf_def.SAR_OK:
        return
    # 调用SKF_Digest函数
    ulRslt.value = skfapi_dll.SKF_Digest(hkey, psrcdata_array, psrcdata_len, pHashDataPointer, byref(ulHashDataLen))
    if ulRslt.value!= skf_def.SAR_OK:
        return
    # 调用SKF_ECCSignData函数
    ulRslt.value = skfapi_dll.SKF_ECCSignData(hcont, pHashDataPointer, ulHashDataLen.value, byref(ecc_sign))
    if ulRslt.value!= skf_def.SAR_OK:
        return
    print("Signature successful")
    # 调用SKF_ECCVerify函数
    ulRslt.value = skfapi_dll.SKF_ECCVerify(hdev, byref(ecc_pub), pHashDataPointer, ulHashDataLen.value, byref(ecc_sign))
    if ulRslt.value!= skf_def.SAR_OK:
        return
    print("Verify signature successful")

    # 关闭相关句柄和释放资源，对应原来C代码中的清理部分
    if hkey:
        skfapi_dll.SKF_CloseHandle(hkey)
    if hcont:
        skfapi_dll.SKF_CloseContainer(hcont)
    if happ:
        skfapi_dll.SKF_CloseApplication(happ)
    if hdev:
        skfapi_dll.SKF_DisConnectDev(hdev)


if __name__ == "__main__":
    main()